home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1997 February / EnigmA AMIGA RUN 15 (1997)(G.R. Edizioni)(IT)[!][issue 1997-02][PLANET CD V].iso / enigma / earcd / utility / utilfile / xfh.lha / XFH / Source / xpk.c < prev   
C/C++ Source or Header  |  1996-11-26  |  40KB  |  1,365 lines

  1. /* xpk.c - routines for the master xpk.library. 
  2.    Copyright (C) 1991, 1992, 1993 Kristian Nielsen.
  3.  
  4.    This file is part of XFH, the compressing file system handler.
  5.  
  6.    This program is free software; you can redistribute it and/or modify
  7.    it under the terms of the GNU General Public License as published by
  8.    the Free Software Foundation; either version 2 of the License, or
  9.    (at your option) any later version.
  10.  
  11.    This program is distributed in the hope that it will be useful,
  12.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.    GNU General Public License for more details.
  15.  
  16.    You should have received a copy of the GNU General Public License
  17.    along with this program; if not, write to the Free Software
  18.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.            */
  19.  
  20. #include "CFS.h"
  21. #include "dossupport.h"
  22.  
  23. #include <utility/hooks.h>
  24. #include <utility/tagitem.h>
  25.  
  26. #include <xpk/xpk.h>
  27.  
  28. #include <string.h>
  29.  
  30. /* These two include files are changing all the time. Hence the #undef. */
  31. #undef XpkFH
  32.  
  33. struct Library *XpkBase;
  34.  
  35. #ifndef min
  36. #define min(a,b) ((a)>(b) ? (b) : (a))
  37. #endif
  38.  
  39. /* 'Conditional' tag - passed only if condition true. */
  40. #define TAGIF(c,t) ((c)?(t):TAG_IGNORE)
  41.  
  42. /* Structure for holding an xpk file unpacked in memory. */
  43. struct unpackedxpk {
  44.   struct xpkmemchunk *first,*last,*current;
  45.   LONG currentpos;
  46. };
  47.  
  48. /* Node in linked list of data buffers. */
  49. struct xpkmemchunk {
  50.   struct xpkmemchunk *next;
  51.   LONG abspos;
  52.   LONG size;
  53.   UBYTE *data;      /* MUST be alloced with dosalloc(). */
  54. };
  55.  
  56. struct XpkFH {
  57.   struct CFSFH cfsfh;
  58.   struct unpackedxpk *unpackedxpk;
  59.   LONG filelen;
  60.   UBYTE *InBuf;     /* Buffer last returned by inhook. */
  61.   UBYTE *OutBuf;    /* Buffer last returned by outhook. */
  62.   LONG InBufLen;    /* Of InBuf. (ToDo: Not really used...) */
  63.   LONG OutBufLen;   /* Of OutBuf. (ToDo: Not really used...) */
  64. };
  65.  
  66. struct XpkLock {
  67.   struct CFSLock cfslock;
  68. };
  69.  
  70.  
  71.  
  72. static struct unpackedxpk *newunpackedxpk(void){
  73.   struct unpackedxpk *p;
  74.   
  75.   if(!dalloc(p)) return NULL;
  76.   /* All fields 0 by default. */
  77.   return p;
  78. }
  79.  
  80. /* NOTE: 'data' should be allocated with dosalloc().
  81.  * NOTE ALSO: Memory block may be larger than 'size' (will be freed by
  82.  * dosfree() ).
  83.  */
  84. static BOOL addxpkmemchunk(struct unpackedxpk *p, UBYTE *data, LONG size )
  85. {
  86.   struct xpkmemchunk *q;
  87.   
  88.   if(!(dalloc(q))) return FALSE;
  89.   q->next=NULL;
  90.   q->size=size;
  91.   q->data=data;
  92.   if(!p->first){
  93.     q->abspos = 0L;
  94.     p->first=p->current=p->last = q;
  95.   }else{
  96.     q->abspos = p->last->abspos+p->last->size;
  97.     p->last->next = q;
  98.     p->last = q;
  99.   }
  100.   return TRUE;
  101. }
  102.  
  103. static void killunpackedxpk(struct unpackedxpk *p){
  104.   struct xpkmemchunk *q,*r;
  105.   
  106.   for(q=p->first;q;q=r){
  107.     r=q->next;
  108.     dfree(q->data);
  109.     dfree(q);
  110.   }
  111.   dfree(p);
  112. }
  113.  
  114. static BOOL seekunpackedxpk(struct unpackedxpk *p, LONG abspos){
  115.    struct xpkmemchunk *q;
  116.    
  117.    if(abspos < 0 || !p->first || p->last->abspos+p->last->size < abspos)
  118.       return (BOOL) (abspos == 0);
  119.    /* Special case: seek just beyond end. */
  120.    if(p->last->abspos+p->last->size == abspos){
  121.         debug(("Seeking to last position in file: %ld.\n",abspos));
  122.       p->current = p->last;
  123.       p->currentpos = abspos;
  124.         return DOSTRUE;
  125.    }
  126.    /* Start at current pos. if possible. */
  127.    q = p->current->abspos <= abspos ? p->current : p->first;
  128.    while(q->abspos+q->size <= abspos) q = q->next;
  129.    p->current = q;
  130.    p->currentpos = abspos;
  131.    return DOSTRUE;
  132. }
  133.  
  134. static BOOL readunpackedxpk(struct unpackedxpk *p, UBYTE *buf, LONG size){
  135.    struct xpkmemchunk *q;
  136.    LONG len,chunkpos;
  137.    
  138.    if(!p->first)
  139.       return (BOOL) (size==0);
  140.    q = p->current;
  141.    while(size>0){
  142.       if(p->last->abspos+p->last->size <= p->currentpos) return FALSE;
  143.       chunkpos=p->currentpos-q->abspos;
  144.       len = min(size,q->size-chunkpos);
  145.       CopyMem(q->data+chunkpos,buf,len);
  146.       size-=len;
  147.       buf+=len;
  148.       p->currentpos+=len;
  149.       if(p->currentpos >= q->abspos+q->size) q=q->next;
  150.       if(q) p->current = q;
  151.    }
  152.    return TRUE;
  153. }
  154.  
  155.  
  156.  
  157. /*------------------------------------------------------------------------*
  158.  * Hooks for Xpk packing / unpacking.
  159.  */
  160.  
  161. /* Structure for private hook data (glob & Xpkfilehandle). */
  162. struct xpkhookdata {
  163.    glb glob;
  164.    struct XpkFH *fh;
  165. };
  166.  
  167.  
  168. /* Free Xpk input buffer if nessesary. */
  169. static void FreeXpkInBuf(struct XpkFH *fh){
  170.  
  171.    /* debug(("FreeXpkInBuf: Checking if buffers allocated...\n")); */
  172.    if(fh->InBuf){
  173.       /* debug(("FreeXpkInBuf: Freeing buffer: %lx,%ld.\n",fh->InBuf,fh->InBufLen)); */
  174.       dosfree(fh->InBuf);
  175.       fh->InBuf = NULL;
  176.    }
  177. }
  178.  
  179. /* Allocate Xpk input buffer. */
  180. static UBYTE *AllocXpkInBuf(struct XpkFH *fh, LONG size){
  181.  
  182.    /* NOTE: I found out (the hard way...) that Xpk expects a buffer
  183.     * 4 bytes larger than requested ... wierd. */
  184.    size+=4;
  185.    FreeXpkInBuf(fh);
  186.    fh->InBufLen=size;
  187.    if(!(fh->InBuf=dosalloc(size))){
  188.       return 0L;
  189.    }
  190.    return fh->InBuf;
  191. }
  192.  
  193. /* Free Xpk output buffer if nessesary. */
  194. static void FreeXpkOutBuf(struct XpkFH *fh){
  195.  
  196.    /* debug(("FreeXpkOutBuf: Checking if buffers allocated...\n")); */
  197.    if(fh->OutBuf){
  198.       /* debug(("FreeXpkOutBuf: Freeing buffer: %lx,%ld.\n",fh->OutBuf,fh->OutBufLen)); */
  199.       dosfree(fh->OutBuf);
  200.       fh->OutBuf = NULL;
  201.    }
  202. }
  203.  
  204. /* Allocate Xpk output buffer. */
  205. static UBYTE *AllocXpkOutBuf(struct XpkFH *fh, LONG size){
  206.  
  207.    /* NOTE: I found out (the hard way...) that Xpk expects a buffer
  208.     * 4 bytes larger than requested ... wierd. */
  209.    size+=4;
  210.    FreeXpkOutBuf(fh);
  211.    fh->OutBufLen=size;
  212.    if(!(fh->OutBuf=dosalloc(size))){
  213.       return 0L;
  214.    }
  215.    return fh->OutBuf;
  216. }
  217.  
  218. /* Transfer control to actual hook function. Shields the actual */
  219. /* hook functions from any ugly assembler-like register considerations. */
  220.  
  221. static LONG __asm __saveds DoXpkHook(register __a0 struct Hook *hook,
  222. register __a1 struct XpkIOMsg *msg)
  223. {
  224.   struct xpkhookdata *hookdata = hook->h_Data;
  225.   LONG ret;
  226.   typedef LONG (*myhooktype)(glb, struct XpkFH *, ULONG, UBYTE **, LONG);
  227.    
  228.   ret = (*(myhooktype)hook->h_SubEntry)
  229.     (hookdata->glob, hookdata->fh, msg->xiom_Type, (UBYTE **) &msg->xiom_Ptr, msg->xiom_Size);
  230.   if(ret) msg->xiom_IOError = hookdata->glob->ioerr;
  231.   return ret;
  232. }
  233.  
  234. /* Calling conventions for hooks. */
  235. /* ToDo: When docs become available, check against this description. */
  236. /* */
  237. /* XpkIOMsg->xiom_IOError is set only in case of non-zero hook return value. */
  238. /* */
  239. /* Big problem: What is XIO_SEEK supposed to return in XpkIOMsg->Ptr? */
  240. /* The masterlib does the wierdest things... However, it (currently!) */
  241. /* only needs a non-zero return in case of succes. */
  242. /* */
  243. /* XIO_GETBUF/XIO_WRITE in xpkunpackout(): It is assumed that only one */
  244. /* buffer will be needed at any time, so that a second XIO_GETBUF may */
  245. /* free the buffer returned by the first. It is also assumed that */
  246. /* XIO_WRITE may grab the buffer it is writing if it was allocated by */
  247. /* XIO_GETBUF. */
  248. /* */
  249.  
  250. /* Read() hook for unpacking. */
  251. static LONG xpkunpackin(glb glob, struct XpkFH *fh, ULONG type, UBYTE **buf, LONG size){
  252.    LONG actuallen;
  253.    
  254. /* debug(("UnpackInHook: Type=%ld, Buf=%lx, Len=%ld.\n",type, *buf,size));*/
  255.    switch(type){
  256.      case XIO_READ:
  257.       if(!*buf){
  258.          if(!(*buf=AllocXpkInBuf(fh,size))) return XPKERR_NOMEM;
  259.       }
  260.       if( (actuallen = xRead(glob, fh->cfsfh.xfh, *buf, size)) != size){
  261.          return actuallen >= 0 ? XPKERR_TRUNCATED : XPKERR_IOERRIN;
  262.       }
  263.       break;
  264.      case XIO_WRITE:
  265.       debug(("Error: xpkunpackin(): Xpk attemps to XIO_WRITE.\n"));
  266.       return XPKERR_NOFUNC;
  267.      case XIO_FREE:
  268.      case XIO_ABORT:
  269.       FreeXpkInBuf(fh); 
  270.       break;
  271.      case XIO_GETBUF:
  272.       if(!(*buf=AllocXpkInBuf(fh,size))) return XPKERR_NOMEM;
  273.       break;
  274.      case XIO_SEEK:
  275.       if( xSeek( glob, fh->cfsfh.xfh, size, OFFSET_CURRENT)<0 ){
  276.          return XPKERR_IOERROUT;
  277.       }
  278.       *buf = (APTR) 4L;   /* VERY strange... */
  279.       break;
  280.      case XIO_TOTSIZE:
  281.       /* debug(("..... XIO_TOTSIZE: no action...\n")); */
  282.       break;
  283.      default:
  284.       debug(("*** PANIC: xpkunpackin(): Unknown type of action requested.\n"));
  285.       return XPKERR_NOFUNC;
  286.    }
  287.    
  288.    return XPKERR_OK;
  289. }
  290.  
  291.  
  292. /* Write() hook for unpacking. */
  293. static LONG xpkunpackout(glb glob, struct XpkFH *fh, ULONG type, UBYTE **buf, LONG size){
  294.    
  295. /* debug(("UnpackOutHook: Type=%ld, Buf=%lx, Len=%ld.\n",type,*buf,size)); */
  296.    switch(type){
  297.      case XIO_READ:
  298.       debug(("Error: xpkunpackout(): Xpk attemps to XIO_READ.\n"));
  299.       return XPKERR_NOFUNC;
  300.      case XIO_WRITE:
  301.       if( *buf == fh->OutBuf /* && size == fh->OutBufLen */ ){
  302.          /* Writing our previously allocated buffer. Just add it to */
  303.          /* the filehandle, and mark it as used. */
  304.             /* NOTE: because of safety margin, the added memory block is */
  305.             /* larger than nesseeary. */
  306.  
  307.          /* debug(("Adding previously allocated buffer to filehandle: %lx\n",*buf)); */
  308.          if(!addxpkmemchunk(fh->unpackedxpk,*buf,size)){
  309.             debug(("Error: xpkunpackout(): Cannot add data.\n"));
  310.             return XPKERR_NOMEM;
  311.          }
  312.          fh->OutBuf = NULL;
  313.          fh->OutBufLen = 0L;
  314.       }else{
  315.          UBYTE *newbuf;
  316.          
  317.          /* debug(("Copying data into filehandle.\n")); */
  318.          if( !(newbuf = dosalloc(size)) ){
  319.             debug(("Error: xpkunpackout(): No memory.\n"));
  320.             return XPKERR_NOMEM;
  321.          }
  322.          CopyMem(*buf,newbuf,size);
  323.          if(!addxpkmemchunk(fh->unpackedxpk,newbuf,size)){
  324.             debug(("Error: xpkunpackout(): Cannot add data.\n"));
  325.             dosfree(newbuf);
  326.             return XPKERR_NOMEM;
  327.          }
  328.       }
  329.       break;
  330.      case XIO_FREE:
  331.      case XIO_ABORT:
  332.       FreeXpkOutBuf(fh);
  333.       break;
  334.      case XIO_GETBUF:
  335.       if( !(*buf = AllocXpkOutBuf(fh,size)) ){
  336.          debug(("Error: xpkunpackout(): Cannot get buffer for xpk.\n"));
  337.          return XPKERR_NOMEM;
  338.       }
  339.       /* debug(("xpkunpackout()/XIO_GETBUF: returning buffer %lx\n",*buf)); */
  340.       break;
  341.      case XIO_SEEK:
  342.         /* Strange... Surely this code is wrong? I mean, there's no file
  343.          * handle, is there? Commented out for now. */
  344. /*      if( xSeek( glob, fh->cfsfh.xfh, size, OFFSET_CURRENT)<0 ){ */
  345. /*         return XPKERR_IOERROUT; */
  346. /*      } */
  347. /*      *buf = (APTR) 4L;   /* VERY strange... */
  348.       debug(("Error: xpkunpackout(): Xpk attempts to XIO_SEEK.\n"));
  349.       return XPKERR_NOFUNC;
  350. /*      break; */
  351.      case XIO_TOTSIZE:
  352.       /* debug(("..... XIO_TOTSIZE: no action...\n")); */
  353.       break;
  354.      default:
  355.       debug(("*** PANIC: xpkunpackout(): Unknown type of action requested.\n"));
  356.       return XPKERR_NOFUNC;
  357.    }
  358.    return XPKERR_OK;
  359. }
  360.  
  361.  
  362. /* Hooks for Xpk packing.
  363.  * Currently, these use simple XpkFH file handles. However, I'm hoping
  364.  * to eventually make them use async I/O.
  365.  * NOTE BIEN: these XpkFH are FAKE, and cannot be used as such safely.
  366.  * Specifically, the cfsfh is not valid (though cfsfh.xfh is).
  367.  */
  368.  
  369. /* NOTE: xpkpackin() / xpkpackout() are also used for unpacking. */
  370. /* Read() hook for packing. */
  371. static LONG xpkpackin(glb glob, struct XpkFH *fh, ULONG type, UBYTE **buf, LONG size){
  372.    LONG actuallen;
  373.    
  374. /* debug(("PackInHook: Type=%ld, Buf=%lx, Len=%ld.\n",type, *buf,size));*/
  375.    switch(type){
  376.      case XIO_READ:
  377.       if(!*buf){
  378.          if(!(*buf=AllocXpkInBuf(fh,size))) return XPKERR_NOMEM;
  379.       }
  380.       if( (actuallen = xRead(glob, fh->cfsfh.xfh, *buf, size)) != size){
  381.          return actuallen >= 0 ? XPKERR_TRUNCATED : XPKERR_IOERRIN;
  382.       }
  383.       break;
  384.      case XIO_WRITE:
  385.       debug(("Error: xpkpackin(): Xpk attemps to XIO_WRITE.\n"));
  386.       return XPKERR_NOFUNC;
  387.      case XIO_FREE:
  388.      case XIO_ABORT:
  389.       FreeXpkInBuf(fh); 
  390.       break;
  391.      case XIO_GETBUF:
  392.       if(!(*buf=AllocXpkInBuf(fh,size))) return XPKERR_NOMEM;
  393.       break;
  394.      case XIO_SEEK:
  395.       if( xSeek( glob, fh->cfsfh.xfh, size, OFFSET_CURRENT)<0 ){
  396.          return XPKERR_IOERROUT;
  397.       }
  398.       *buf = (APTR) 4L;   /* VERY strange... */
  399.       break;
  400.      case XIO_TOTSIZE:
  401.       /* debug(("..... XIO_TOTSIZE: no action...\n")); */
  402.       break;
  403.      default:
  404.       debug(("*** PANIC: xpkpackin(): Unknown type of action requested.\n"));
  405.       return XPKERR_NOFUNC;
  406.    }
  407.    
  408.    return XPKERR_OK;
  409. }
  410.  
  411.  
  412. /* Write() hook for packing. */
  413. static LONG xpkpackout(glb glob, struct XpkFH *fh, ULONG type, UBYTE **buf, LONG size){
  414.    
  415. /* debug(("PackOutHook: Type=%ld, Buf=%lx, Len=%ld.\n",type,*buf,size));*/
  416.    switch(type){
  417.      case XIO_READ:
  418.       debug(("Error: xpkpackout(): Xpk attemps to XIO_READ.\n"));
  419.       return XPKERR_NOFUNC;
  420.      case XIO_WRITE:
  421.       if(xWrite(glob, fh->cfsfh.xfh, *buf, size) != size){
  422.          return XPKERR_IOERROUT;
  423.       }
  424.       break;
  425.      case XIO_FREE:
  426.      case XIO_ABORT:
  427.       FreeXpkOutBuf(fh);
  428.       break;
  429.      case XIO_GETBUF:
  430.       if( !(*buf = AllocXpkOutBuf(fh,size)) ){
  431.          debug(("Error: xpkpackout(): Cannot get buffer for xpk.\n"));
  432.          return XPKERR_NOMEM;
  433.       }
  434.       /* debug(("xpkpackout()/XIO_GETBUF: returning buffer %lx\n",*buf)); */
  435.       break;
  436.      case XIO_SEEK:
  437.       if( xSeek( glob, fh->cfsfh.xfh, size, OFFSET_CURRENT)<0 ){
  438.          return XPKERR_IOERROUT;
  439.       }
  440.       *buf = (APTR) 4L;   /* VERY strange... */
  441.       break;
  442.      case XIO_TOTSIZE:
  443.       /* debug(("..... XIO_TOTSIZE: no action...\n")); */
  444.       break;
  445.      default:
  446.       debug(("*** PANIC: xpkpackout(): Unknown type of action requested.\n"));
  447.       return XPKERR_NOFUNC;
  448.    }
  449.    return XPKERR_OK;
  450. }
  451.  
  452. /*------------------------------------------------------------------------*
  453.  * Low-level interface to Xpk functions.
  454.  */
  455.  
  456.  
  457. /* The following code is there to support pre-2.0 OS versions. The
  458.  * problem is that Xpk insists on doing OpenLibrary() itself, which
  459.  * causes the dreaded ASYNCPKT guru.
  460.  */
  461.  
  462. struct xpkunpackmsg{
  463.    struct Message msg;
  464.    void (*func)();
  465.    glb glob;
  466.    struct TagItem *tags;
  467.    LONG result;
  468. };
  469.  
  470. struct xpkexammsg{
  471.    struct Message msg;
  472.    void (*func)();
  473.    glb glob;
  474.    struct XpkFib *fib;
  475.    struct TagItem *tags;
  476.    LONG result;
  477. };
  478.  
  479. struct xpkpackmsg{
  480.    struct Message msg;
  481.    void (*func)();
  482.    glb glob;
  483.    struct TagItem *tags;
  484.    LONG result;
  485. };
  486.  
  487. static void __asm CallXpkUnpackTags(register __a0 struct xpkunpackmsg *msg){
  488.    struct MsgPort *port;
  489.    
  490.    debug(("Calling XpkUnpack(%lx)...", msg->tags ));
  491.    port = msg->glob->ioport;
  492.    if(msg->glob->ioport=CreatePort(NULL,0L)){
  493.       msg -> result = XpkUnpack(msg->tags);
  494.       DeletePort(msg->glob->ioport);
  495.    }else{
  496.       debug(("(no port)"));
  497.       msg->result = XPKERR_NOMEM;
  498.    }
  499.    msg->glob->ioport = port;
  500.    debug(("=%ld\n",msg->result));
  501. }
  502.  
  503.  
  504. static void __asm CallXpkExamine(register __a0 struct xpkexammsg *msg){
  505.    struct MsgPort *port;
  506.    
  507.    debug(("Calling XpkExamine(%lx,%lx)...", msg->fib, msg->tags ));
  508.    port = msg->glob->ioport;
  509.    if(msg->glob->ioport=CreatePort(NULL,0L)){
  510.       msg -> result = XpkExamine(msg->fib, msg->tags);
  511.       DeletePort(msg->glob->ioport);
  512.    }else{
  513.       debug(("(no port)"));
  514.       msg->result = XPKERR_NOMEM;
  515.    }
  516.    msg->glob->ioport = port;
  517.    debug(("=%ld\n",msg->result));
  518. }
  519.  
  520.  
  521. static void __asm CallXpkPackTags(register __a0 struct xpkpackmsg *msg){
  522.    struct MsgPort *port;
  523.    
  524.    debug(("Calling XpkPack(%lx)...", msg->tags ));
  525.    port = msg->glob->ioport;
  526.    if(msg->glob->ioport=CreatePort(NULL,0L)){
  527.       msg -> result = XpkPack(msg->tags);
  528.       DeletePort(msg->glob->ioport);
  529.    }else{
  530.       debug(("(no port)"));
  531.       msg->result = XPKERR_NOMEM;
  532.    }
  533.    msg->glob->ioport = port;
  534.    debug(("=%ld\n",msg->result));
  535. }
  536.  
  537.  
  538. static LONG MyXpkUnpackTags( glb glob, ULONG firsttag, ... ){
  539.    /* Cannot call xpk from a Task (or handler) before KS 2.0. */
  540.    if( ((struct Library *)glob->DOSBase)->lib_Version >= 36){
  541.       return XpkUnpack( (struct TagItem *)&firsttag );
  542.    }else{
  543.       struct xpkunpackmsg msg,*msg2;
  544.       extern void DoDOSSeg();
  545.       struct MsgPort *procid;
  546.    
  547.       msg.msg.mn_Node.ln_Succ=NULL;
  548.       msg.msg.mn_Node.ln_Pred=NULL;
  549.       msg.msg.mn_Node.ln_Name=NULL;
  550.       msg.msg.mn_Node.ln_Type=NT_MESSAGE;
  551.       msg.msg.mn_Node.ln_Pri=0;
  552.       msg.msg.mn_ReplyPort=glob->xpkport;
  553.       msg.msg.mn_Length=sizeof(msg);
  554.       msg.func=(void (*)()) CallXpkUnpackTags;
  555.       msg.glob = glob;
  556.       msg.tags = (struct TagItem *)&firsttag;
  557.  
  558.       if(!(procid=CreateProc   /* Lets pray that 10K stack is enough... */
  559.         ("XpkUnpack()",glob->mytask->tc_Node.ln_Pri,(BPTR)((ULONG)DoDOSSeg>>2),10000L)))
  560.         return XPKERR_NOMEM;
  561.    
  562.       PutMsg(procid,(struct Message *)&msg);
  563.       do WaitPort(glob->xpkport);
  564.       while(!(msg2=(struct xpkunpackmsg *)GetMsg(glob->xpkport)));
  565.  
  566. #ifdef DEBUG
  567.       if(msg2!=&msg)
  568.          KPrintF("ERROR: bogus return message: &msg=%lx msg2=%lx\n",&msg,msg2);
  569. #endif
  570.       return msg2->result;
  571.    }
  572. }
  573.  
  574. static LONG MyXpkExamine( glb glob, struct XpkFib *fib, ULONG firsttag, ... ){
  575.    /* Cannot call xpk from a Task (or handler) before KS 2.0. */
  576.    if( ((struct Library *)glob->DOSBase)->lib_Version >= 36){
  577.       return XpkExamine( fib, (struct TagItem *)&firsttag );
  578.    }else{
  579.       struct xpkexammsg msg,*msg2;
  580.       extern void DoDOSSeg();
  581.       struct MsgPort *procid;
  582.    
  583.       msg.msg.mn_Node.ln_Succ=NULL;
  584.       msg.msg.mn_Node.ln_Pred=NULL;
  585.       msg.msg.mn_Node.ln_Name=NULL;
  586.       msg.msg.mn_Node.ln_Type=NT_MESSAGE;
  587.       msg.msg.mn_Node.ln_Pri=0;
  588.       msg.msg.mn_ReplyPort=glob->xpkport;
  589.       msg.msg.mn_Length=sizeof(msg);
  590.       msg.func=(void (*)()) CallXpkExamine;
  591.       msg.glob = glob;
  592.       msg.fib = fib;
  593.       msg.tags = (struct TagItem *)&firsttag;
  594.  
  595.       if(!(procid=CreateProc   /* Lets pray that 10K stack is enough... */
  596.         ("XpkExamine()",glob->mytask->tc_Node.ln_Pri,(BPTR)((ULONG)DoDOSSeg>>2),10000L)))
  597.         return XPKERR_NOMEM;
  598.    
  599.       PutMsg(procid,(struct Message *)&msg);
  600.       do WaitPort(glob->xpkport);
  601.       while(!(msg2=(struct xpkexammsg *)GetMsg(glob->xpkport)));
  602.  
  603. #ifdef DEBUG
  604.       if(msg2!=&msg)
  605.          KPrintF("ERROR: bogus return message: &msg=%lx msg2=%lx\n",&msg,msg2);
  606. #endif
  607.       return msg2->result;
  608.    }
  609. }
  610.  
  611. static LONG MyXpkPackTags( glb glob, ULONG firsttag, ... ){
  612.    /* Cannot call Xpk from a Task (or handler) before KS 2.0. */
  613.    if( ((struct Library *)glob->DOSBase)->lib_Version >= 36){
  614.       return XpkPack( (struct TagItem *)&firsttag );
  615.    }else{
  616.       struct xpkpackmsg msg,*msg2;
  617.       extern void DoDOSSeg();
  618.       struct MsgPort *procid;
  619.    
  620.       msg.msg.mn_Node.ln_Succ=NULL;
  621.       msg.msg.mn_Node.ln_Pred=NULL;
  622.       msg.msg.mn_Node.ln_Name=NULL;
  623.       msg.msg.mn_Node.ln_Type=NT_MESSAGE;
  624.       msg.msg.mn_Node.ln_Pri=0;
  625.       msg.msg.mn_ReplyPort=glob->xpkport;
  626.       msg.msg.mn_Length=sizeof(msg);
  627.       msg.func=(void (*)())CallXpkPackTags;
  628.       msg.glob = glob;
  629.       msg.tags = (struct TagItem *)&firsttag;
  630.  
  631.       if(!(procid=CreateProc   /* Lets pray that 10K stack is enough... */
  632.         ("XpkPack()",glob->mytask->tc_Node.ln_Pri,(BPTR)((ULONG)DoDOSSeg>>2),10000L)))
  633.         return XPKERR_NOMEM;
  634.    
  635.       PutMsg(procid,(struct Message *)&msg);
  636.       do WaitPort(glob->xpkport);
  637.       while(!(msg2=(struct xpkpackmsg *)GetMsg(glob->xpkport)));
  638.  
  639. #ifdef DEBUG
  640.       if(msg2!=&msg)
  641.          KPrintF("ERROR: bogus return message: &msg=%lx msg2=%lx\n",&msg,msg2);
  642. #endif
  643.       return msg2->result;
  644.    }
  645. }
  646.  
  647.  
  648. /* This function opens an existing file in the xpk format, unpacking
  649.  * it to memory with the help of the xpk.library. Note that due to
  650.  * limitation in the current interface of xpk.library, the whole file
  651.  * must be unpacked at once, which is more speed efficient (and by far
  652.  * the easiest to implement), but requires rather a lot of memory
  653.  * (potentially requiring the data to reside 2-3 times in main memory
  654.  * simultaneously) and could result in memory fragmentation.
  655.  */
  656. struct XpkFH *XpkOpenOldFile( glb glob, struct FileHandle *xfh ){
  657.    struct XpkFH *fh;
  658.    LONG res;
  659.    LONG inlen;
  660.    struct Hook inhook,outhook;
  661.    struct xpkhookdata indata,outdata;
  662.    
  663.    if(!dalloc(fh)){
  664.       OUTOFMEM;
  665.       return NULL;
  666.    }
  667.    fh->cfsfh.objtype = XPKOBJECT;
  668.    fh->cfsfh.mode = MODE_OLDFILE;
  669.    fh->cfsfh.xfh = xfh;
  670.    fh->cfsfh.f = &Xpkfunc;
  671.    /* fh->cfsfh.filename and fh->cfsfh.parent NULL by default. */
  672.    
  673.    if(!(fh->unpackedxpk=newunpackedxpk())){
  674.       OUTOFMEM;
  675.       dfree(fh);
  676.       return NULL;
  677.    }
  678.    
  679.    inhook.h_Entry = (ULONG (*)())DoXpkHook;
  680.    inhook.h_SubEntry = (ULONG (*)())xpkunpackin;
  681.    indata.glob=glob;
  682.    indata.fh=fh;
  683.    inhook.h_Data = &indata;
  684.    outhook.h_Entry = (ULONG (*)())DoXpkHook;
  685.    outhook.h_SubEntry = (ULONG (*)())xpkunpackout;
  686.    outdata.glob=glob;
  687.    outdata.fh=fh;
  688.    outhook.h_Data = &outdata;
  689.  
  690.    /* Get length of file, if possible. */
  691.    inlen = xFileSizeXfh( glob, xfh );
  692.  
  693.    glob->ioerr = 0L;          /* Set by hookfuncs if adequate. */
  694.    res = MyXpkUnpackTags( glob,
  695.             XPK_InHook, &inhook,
  696.             XPK_OutHook, &outhook,
  697.             XPK_Password, glob->xpkpassword,
  698.             TAGIF(inlen!=-1L,XPK_InLen), inlen,
  699.             TAGIF(glob->xpksetpri,XPK_TaskPri), glob->xpkpri,
  700.             TAG_DONE
  701.          );
  702.     debug(("XpkUnPack() returned: %ld\n",res));
  703.    FreeXpkInBuf(fh);
  704.    FreeXpkOutBuf(fh);
  705.    
  706.    if(res != XPKERR_OK){
  707.       if(!glob->ioerr){
  708.          /* ToDo: Since no adequate AmigaDOS error code exists, we */
  709.          /* should perhaps open a requester to inform the user of */
  710.          /* the problem (showing an XpkErr)? */
  711.          glob->ioerr = ERROR_OBJECT_WRONG_TYPE;  /* More likely out of memory. */
  712.       }
  713.       killunpackedxpk(fh->unpackedxpk);
  714.       dfree(fh);
  715.       return NULL;
  716.    }
  717.    if(fh->unpackedxpk->first)
  718.       fh->filelen = fh->unpackedxpk->last->abspos 
  719.                   + fh->unpackedxpk->last->size; /* else 0 by default. */
  720.    return fh;
  721. }
  722.  
  723.  
  724. /* Perform a XpkExamine() on an UFS file handle. */
  725. BOOL XpkExamine_FH( glb glob, struct FileHandle *xfh, struct XpkFib *fib ){
  726.    LONG res;
  727.    LONG inlen;
  728.    struct XpkFH *fh;
  729.    struct Hook inhook;
  730.    struct xpkhookdata indata;
  731.    
  732.    if(!dalloc(fh)){ /* NOTE: NOT a real xpkfilehandle (only InBuf is used). */
  733.       OUTOFMEM;
  734.       return FALSE;
  735.    }
  736.    fh->cfsfh.xfh = xfh;
  737.  
  738.    inhook.h_Entry = (ULONG (*)())DoXpkHook;
  739.    inhook.h_SubEntry = (ULONG (*)())xpkunpackin;
  740.     indata.glob=glob;
  741.     indata.fh=fh;
  742.    inhook.h_Data = &indata;
  743.  
  744.    /* Get length of file, if possible. */
  745.    inlen = xFileSizeXfh( glob, xfh );
  746.    
  747.    glob->ioerr = 0L;          /* Set by hookfuncs if adequate. */
  748.    res = MyXpkExamine( glob, fib,
  749.             XPK_InHook,&inhook,
  750.             TAGIF(inlen!=-1L,XPK_InLen), inlen,
  751.             TAGIF(glob->xpksetpri,XPK_TaskPri), glob->xpkpri,
  752.             TAG_DONE
  753.          );
  754.     debug(("XpkExamine() returned: %ld\n",res));
  755.    FreeXpkInBuf(fh);
  756.    dfree(fh);
  757.       /* Need a better error message here. */
  758.    if( res && !glob->ioerr ) glob->ioerr = ERROR_OBJECT_WRONG_TYPE;
  759.     return (BOOL)( res==XPKERR_OK );
  760. }    
  761.  
  762.  
  763. /* This is the function that does the actual compression (using xpk) from
  764.  * one file handle to another.
  765.  */
  766. static BOOL XpkPackFH2FH(glb glob, struct FileHandle *srcxfh,
  767.                          LONG inlen, struct FileHandle *dstxfh){
  768.    struct XpkFH *srcxpkfh,*dstxpkfh;  /* NOTE: these are FAKE/invalid. */
  769.    LONG res;
  770.    LONG outlen;                     /* Dummy variable. */
  771.    struct Hook inhook,outhook;
  772.    struct xpkhookdata indata,outdata;
  773.    
  774.    /* Create the two fake XpkFH filehandles for the hooks. */
  775.    if(!dalloc(srcxpkfh)){
  776.       OUTOFMEM;
  777.       return FALSE;
  778.    }
  779.    if(!dalloc(dstxpkfh)){
  780.       OUTOFMEM;
  781.       dfree(srcxpkfh);
  782.       return FALSE;
  783.    }
  784.    srcxpkfh->cfsfh.xfh = srcxfh;   /* Buffer pointers NULL by default. */
  785.    dstxpkfh->cfsfh.xfh = dstxfh;   /* Buffer pointers NULL by default. */
  786.    
  787.    /* Set up hooks. */
  788.    inhook.h_Entry = (ULONG (*)())DoXpkHook;
  789.    inhook.h_SubEntry = (ULONG (*)())xpkpackin;
  790.    indata.glob=glob;
  791.    indata.fh=srcxpkfh;
  792.    inhook.h_Data = &indata;
  793.    outhook.h_Entry = (ULONG (*)())DoXpkHook;
  794.    outhook.h_SubEntry = (ULONG (*)())xpkpackout;
  795.    outdata.glob=glob;
  796.    outdata.fh=dstxpkfh;
  797.    outhook.h_Data = &outdata;
  798.  
  799.    glob->ioerr = 0L;          /* Set by hookfuncs if adequate. */
  800.    res = MyXpkPackTags( glob,
  801.       XPK_InHook,&inhook,
  802.       XPK_OutHook,&outhook,
  803.       XPK_InLen,inlen,
  804.       XPK_PackMethod,glob->packmode,
  805.       XPK_StepDown,glob->stepdown,
  806.       XPK_Password,glob->xpkpassword,
  807.       XPK_GetOutLen,&outlen, /* NOTE: not used, buf xpk.doc says needed. */
  808.       TAGIF(glob->xpksetpri,XPK_TaskPri), glob->xpkpri,
  809.       TAG_DONE
  810.     );
  811.     debug(("XpkPack() returned: %ld\n",res));
  812.    
  813.    FreeXpkInBuf(srcxpkfh);
  814.    FreeXpkOutBuf(dstxpkfh);
  815.    dfree(srcxpkfh);
  816.    dfree(dstxpkfh);
  817.  
  818.    if(res != XPKERR_OK){
  819.       if(!glob->ioerr){
  820.          /* ToDo: Since no adequate AmigaDOS error code exists, we */
  821.          /* should perhaps open a requester to inform the user of */
  822.          /* the problem (showing an XpkErr)? */
  823.          glob->ioerr = ERROR_OBJECT_WRONG_TYPE;  /* More likely out of memory. */
  824.       }
  825.       return FALSE;
  826.    }
  827.    return TRUE;
  828. }
  829.  
  830.  
  831. /* This is the function that does the actual compression (using xpk) from
  832.  * one file handle to another.
  833.  */
  834. static BOOL XpkUnPackFH2FH(glb glob, struct FileHandle *srcxfh,
  835.                          LONG inlen, struct FileHandle *dstxfh){
  836.    struct XpkFH *srcxpkfh,*dstxpkfh;  /* NOTE: these are FAKE/invalid. */
  837.    LONG res;
  838.    struct Hook inhook,outhook;
  839.    struct xpkhookdata indata,outdata;
  840.    
  841.    /* Create the two fake XpkFH filehandles for the hooks. */
  842.    if(!dalloc(srcxpkfh)){
  843.       OUTOFMEM;
  844.       return FALSE;
  845.    }
  846.    if(!dalloc(dstxpkfh)){
  847.       OUTOFMEM;
  848.       dfree(srcxpkfh);
  849.       return FALSE;
  850.    }
  851.    srcxpkfh->cfsfh.xfh = srcxfh;   /* Buffer pointers NULL by default. */
  852.    dstxpkfh->cfsfh.xfh = dstxfh;   /* Buffer pointers NULL by default. */
  853.    
  854.    /* Set up hooks. */
  855.    inhook.h_Entry = (ULONG (*)())DoXpkHook;
  856.    inhook.h_SubEntry = (ULONG (*)())xpkpackin;
  857.    indata.glob=glob;
  858.    indata.fh=srcxpkfh;
  859.    inhook.h_Data = &indata;
  860.    outhook.h_Entry = (ULONG (*)())DoXpkHook;
  861.    outhook.h_SubEntry = (ULONG (*)())xpkpackout;
  862.    outdata.glob=glob;
  863.    outdata.fh=dstxpkfh;
  864.    outhook.h_Data = &outdata;
  865.  
  866.    glob->ioerr = 0L;          /* Set by hookfuncs if adequate. */
  867.    res = MyXpkUnpackTags( glob,
  868.       XPK_InHook,&inhook,
  869.       XPK_OutHook,&outhook,
  870.       XPK_InLen,inlen,
  871.       XPK_Password,glob->xpkpassword,
  872.       TAGIF(glob->xpksetpri,XPK_TaskPri), glob->xpkpri,
  873.       TAG_DONE
  874.     );
  875.    debug(("XpkUnPack() returned: %ld\n",res));
  876.    
  877.    FreeXpkInBuf(srcxpkfh);
  878.    FreeXpkOutBuf(dstxpkfh);
  879.    dfree(srcxpkfh);
  880.    dfree(dstxpkfh);
  881.  
  882.    if(res != XPKERR_OK){
  883.       if(!glob->ioerr){
  884.          /* ToDo: Since no adequate AmigaDOS error code exists, we */
  885.          /* should perhaps open a requester to inform the user of */
  886.          /* the problem (showing an XpkErr)? */
  887.          glob->ioerr = ERROR_OBJECT_WRONG_TYPE;  /* More likely out of memory. */
  888.       }
  889.       return FALSE;
  890.    }
  891.    return TRUE;
  892. }
  893.  
  894.  
  895. /* NOTE BIEN: This function preserves the lock! */
  896. struct XpkFH *XpkOpenOldFileFromCopyOfLock( glb glob, struct XpkLock *lock ){
  897.    struct FileHandle *xfh;
  898.    struct XpkFH *fh;
  899.    
  900.    if(!(xfh = xOpenFromCopyOfLock(glob, lock->cfslock.xlock))){
  901.       debug(("Unable to xOpenFromLock(): %ld.\n",glob->ioerr));
  902.       return NULL;
  903.    }
  904.    fh = XpkOpenOldFile( glob, xfh );
  905.    if(!fh){
  906.       LONG saveioerr = glob->ioerr;
  907.       xClose(glob,xfh);
  908.       glob->ioerr = saveioerr;
  909.    }
  910.    return fh;
  911. }
  912.  
  913.  
  914. /* Check if a given filehandle belongs to an Xpk file. glob->ioerr
  915.  * set and FALSE returned in case of error.
  916.  */
  917.  
  918. BOOL IsXpkFile( glb glob, struct FileHandle *xfh ){
  919.    struct XpkFib fib;
  920.    
  921.    if(!XpkExamine_FH(glob, xfh, &fib) ){
  922.       debug(("Error: IsXpkFile: XpkExamine_FH returned error\n"));
  923.       return FALSE;
  924.    }
  925.    else if(fib.xf_Type == XPKTYPE_PACKED )
  926.       return TRUE;
  927.    else
  928.    {
  929.       glob->ioerr = 0L;
  930.       return FALSE;
  931.    }
  932. }
  933.  
  934.  
  935. /* This is the main entry to the automatic compression, and is the
  936.  * function passed to TransFormFile().
  937.  */
  938. BOOL PackFile2File(glb glob, struct FileHandle *srcxfh,
  939.                    struct FileHandle *dstxfh, void *dummy){
  940.    LONG srcsize;
  941.    
  942.    srcsize = xGetFileSize(glob, srcxfh);
  943.    if(srcsize == -1L){
  944.       debug(("Error: PackFile2File(): Could not obtain file length.\n"));
  945.       return FALSE;
  946.    }
  947.    return XpkPackFH2FH(glob, srcxfh, srcsize, dstxfh);
  948. }
  949.  
  950.  
  951. /* This function is passed to TransFormFile() to unpack a file to another
  952.  * file (to handle Write() to an Xpk file).
  953.  */
  954. BOOL UnPackFile2File(glb glob, struct FileHandle *srcxfh,
  955.                      struct FileHandle *dstxfh, void *dummy){
  956.    LONG srcsize;
  957.    
  958.    srcsize = xGetFileSize(glob, srcxfh);
  959.    if(srcsize == -1L){
  960.       debug(("Error: UnPackFile2File(): Could not obtain file length.\n"));
  961.       return FALSE;
  962.    }
  963.    return XpkUnPackFH2FH(glob, srcxfh, srcsize, dstxfh);
  964. }
  965.  
  966.  
  967. /*------------------------------------------------------------------------*
  968.  * Virtual functions for Open(), Read(), Lock() etc.
  969.  */
  970.  
  971. LONG Xpk_Read( glb glob, struct XpkFH *fh, UBYTE *buf, LONG len ){
  972.  
  973.    if( fh->unpackedxpk->currentpos+len > fh->filelen )
  974.       len = fh->filelen - fh->unpackedxpk->currentpos;
  975.    if( len <= 0 ) return 0L;
  976.    
  977.    if(!readunpackedxpk(fh->unpackedxpk, buf, len )){
  978.       return -1L;
  979.    }
  980.    return len;
  981. }
  982.  
  983.  
  984. LONG Xpk_Seek( glb glob, struct XpkFH *fh, LONG pos, LONG offset ){
  985.     LONG abspos;
  986.     LONG oldpos = fh->unpackedxpk->currentpos;
  987.    
  988.    if( offset != OFFSET_BEGINNING &&
  989.        offset != OFFSET_CURRENT   &&
  990.        offset != OFFSET_END ){
  991.       debug(("Error: Xpk: Bad offset value for Seek(): %ld\n",offset));
  992.       glob->ioerr = ERROR_ACTION_NOT_KNOWN;
  993.       return -1L;
  994.    }
  995.    abspos = abs_seek_pos( fh->unpackedxpk->currentpos, fh->filelen, pos, offset );
  996.    if( abspos < 0 || abspos > fh->filelen ){
  997.       debug(("Error: Xpk: Bad abs. pos. in Seek(): %ld\n",abspos));
  998.       glob->ioerr = ERROR_SEEK_ERROR;
  999.       return -1L;
  1000.    }
  1001.     debug(("XpkSeek(): fh=%lx, pos=%ld, offset=%ld, abspos=%ld\n",fh,pos,offset,abspos));
  1002.    seekunpackedxpk(fh->unpackedxpk,abspos);
  1003.    
  1004.    return oldpos;
  1005. }
  1006.  
  1007.  
  1008. BOOL Xpk_Close( glb glob, struct XpkFH *fh ){
  1009.   BOOL res;
  1010.    
  1011.   if(!fh->cfsfh.xfh){
  1012.     debug(("Xpk_Close(): Bad fh.\n"));
  1013.     glob->ioerr = ERROR_OBJECT_WRONG_TYPE;
  1014.     return FALSE;
  1015.   }
  1016.   res = xClose( glob, fh->cfsfh.xfh );
  1017.   if( res ){
  1018.     killunpackedxpk(fh->unpackedxpk);
  1019.     XObjUnStuffFH(glob, &fh->cfsfh);
  1020.     dfree(fh);
  1021.   }else{
  1022.     debug(("ERROR: Xpk: xClose() returned false - mem not freed.\n"));
  1023.   }
  1024.   return res;
  1025. }
  1026.  
  1027.  
  1028. /* Xpk_Write() needs to do some magic to prepare the file for writing. The
  1029.  * idea is to replace the file (on disk) with the unpacked data, then make
  1030.  * the file handle look like a CFSFH.
  1031.  *
  1032.  * One possibility would be to write the data in memory. However, since
  1033.  * the file could have changed since this Open(), it's safer to
  1034.  * uncompress the file again.
  1035.  */
  1036. LONG Xpk_Write(glb glob, struct XpkFH *fh, UBYTE *buf, LONG len){
  1037.   BOOL res;
  1038.   char *filename = fh->cfsfh.filename;
  1039.   struct FileLock *xlock = fh->cfsfh.parent->xlock;
  1040.   struct FileHandle *xfh = fh->cfsfh.xfh;
  1041.   LONG currentpos;
  1042.  
  1043.   if(!glob->allowappend){
  1044.     debug(("Xpk_Write(): Appendmode not set - failing.\n"));
  1045.     glob->ioerr = ERROR_ACTION_NOT_KNOWN;
  1046.     return -1L;
  1047.   }
  1048.   if(!xfh){
  1049.     debug(("XpkWrite(): Bad fh.\n"));
  1050.     glob->ioerr = ERROR_OBJECT_WRONG_TYPE;
  1051.     return -1L;
  1052.   }
  1053.   if(!filename){
  1054.     debug(("Error: Xpk_Write(): no name info.\n"));
  1055.     glob->ioerr = ERROR_ACTION_NOT_KNOWN;
  1056.     return -1L;
  1057.   }
  1058.   debug(("Attempting to uncompress file %s.\n",filename));
  1059.   if(!xChangeMode(glob, CHANGE_FH, xfh, MODE_NEWFILE)){
  1060.     debug(("Error: Xpk_Write(): xChangeMode(): %ld.\n",glob->ioerr));
  1061.     return -1L;
  1062.   }
  1063.   if(-1L == xSeek(glob, xfh, 0L, OFFSET_BEGINNING)){
  1064.     debug(("Error: Xpk_Write(): Could not seek to start: %ld.\n",glob->ioerr));
  1065.     return -1L;
  1066.   }
  1067.   res = TransformXFH(glob, xfh, xlock, filename, UnPackFile2File, NULL);
  1068.   debug(("TransformFile() returned: %ld.\n",res));
  1069.   fh->cfsfh.xfh = xfh = NULL;   /* The handle was closed by TransformFile(). */
  1070.   if(!res){
  1071.     SAVEIOERR;
  1072.     /* Bad luck! The uncompress didn't work. Since our xfh is gone, we'll
  1073.      * have to do some magic to save as much as possible.
  1074.      */
  1075.     if( !(xfh=xOpen(glob, xlock, filename, fh->cfsfh.mode)) ){
  1076.       debug(("Error: File %s could not be re-opened: %d.\n",filename,glob->ioerr));
  1077.       /* Nothing to do about it, really... */
  1078.     }
  1079.     RESTIOERR;
  1080.     return -1L;
  1081.   }
  1082.   if( !(xfh=xOpen(glob, xlock, filename, fh->cfsfh.mode)) ){
  1083.     debug(("Error: File %s could not be re-opened: %d.\n",filename,glob->ioerr));
  1084.     /* Nothing to do about it, really... */
  1085.     return -1L;
  1086.   }
  1087.   fh->cfsfh.xfh = xfh;
  1088.   currentpos = fh->unpackedxpk->currentpos;
  1089.   killunpackedxpk(fh->unpackedxpk);
  1090.   if(!glob->compressreadwrite) XObjUnStuffFH(glob, &fh->cfsfh);
  1091.   XObjStealXpkFH(glob, &fh->cfsfh);
  1092.   if(-1L == xSeek(glob, xfh, currentpos, OFFSET_BEGINNING)){
  1093.     debug(("Error: Xpk_Write(): Could not seek to right pos: %ld.\n",glob->ioerr));
  1094.     return -1L;
  1095.   }else{
  1096.     return XObjWrite(glob, &fh->cfsfh, buf, len);
  1097.   }
  1098. }
  1099.  
  1100.  
  1101. struct XpkLock *XpkMakeLock( glb glob, struct FileLock *xlock, LONG mode ){
  1102.     struct XpkLock *newlock;
  1103.     
  1104.     if( !dalloc(newlock) ){
  1105.         OUTOFMEM;
  1106.         return NULL;
  1107.     }
  1108.     newlock->cfslock.objtype = XPKOBJECT;
  1109.     newlock->cfslock.mode = mode;
  1110.     newlock->cfslock.xlock = xlock;
  1111.     newlock->cfslock.f = &Xpkfunc;
  1112.    newlock->cfslock.refcount = 0;    /* NOTE: NOT used for XpkObject's. */
  1113.     return newlock;
  1114. }
  1115.  
  1116.  
  1117. struct XpkLock *XpkDupLock( glb glob, struct XpkLock *lock ){
  1118.    struct XpkLock *newlock;
  1119.  
  1120.    /* XPKOBJECT locks have their xLocks xDupLock'ed, and the rest of
  1121.     * the fields are just copied vanilla.
  1122.     */
  1123.    if( !dalloc(newlock) ){
  1124.       OUTOFMEM;
  1125.       return 0L;
  1126.    }
  1127.    *newlock = *lock;
  1128.    newlock->cfslock.refcount = 0L;   /* Again: refcount is not used. */
  1129.    if( !(newlock->cfslock.xlock = xDupLock(glob, lock->cfslock.xlock)) ){
  1130.       dfree(newlock);
  1131.       return 0L;
  1132.    }
  1133.    return newlock;   
  1134. }
  1135.  
  1136.  
  1137. /* NOTE BIEN: The parent lock is a XOBJECT, not a XPKOBJECT! */
  1138. struct CFSLock *XpkParentDir( glb glob, struct XpkLock *lock ){
  1139.     struct FileLock *xlock;
  1140.     struct CFSLock *newlock;
  1141.     
  1142.     if( !(xlock = xParentDir(glob, lock->cfslock.xlock)) ){
  1143.         return 0L;
  1144.     }
  1145.     newlock = XObjMakeLock( glob, xlock, ACCESS_READ );
  1146.     if( !newlock ){
  1147.         LONG saveioerr = glob->ioerr;
  1148.         xUnLock(glob, xlock);
  1149.         glob->ioerr = saveioerr;
  1150.     }
  1151.     return newlock;
  1152. }
  1153.  
  1154.  
  1155. /* NOTE BIEN: The parent lock is a XOBJECT, not a XPKOBJECT! */
  1156. struct CFSLock *XpkParentFH( glb glob, struct XpkFH *fh ){
  1157.     
  1158.     return XObjParentFH(glob, &fh->cfsfh);
  1159. }
  1160.  
  1161.  
  1162. BOOL XpkUnLock( glb glob, struct XpkLock *lock ){
  1163.     BOOL err;
  1164.  
  1165.    if(lock->cfslock.refcount){
  1166.       /* This should NOT have happened! */
  1167.       debug(("\n\n***PANIC***: XpkUnLock: Nonzero refcount in lock (%ld).\n",lock->cfslock.refcount));
  1168.       return DOSFALSE;
  1169.    }
  1170.     err = xUnLock(glob, lock->cfslock.xlock);
  1171.       
  1172.     /* Now, what if the UnLock fails? I guess it's best to return FALSE
  1173.      * and let the lock live.
  1174.      */
  1175.     if(!err) return DOSFALSE;
  1176.     dfree(lock);
  1177.     return DOSTRUE;
  1178. }
  1179.  
  1180.  
  1181. BOOL XpkSameLock(glb glob, struct XpkLock *l1, struct XpkLock *l2 ){
  1182.     return (BOOL) (xSameLock( glob, l1->cfslock.xlock, l2->cfslock.xlock ) == LOCK_SAME);
  1183. }
  1184.  
  1185. LONG ATUL ( char *Ptr ){
  1186.     UWORD Index;
  1187.     LONG LW;
  1188.  
  1189.     for (Index=0,LW=0L;Index<8;Index++)
  1190.       LW=(LW<<4)+(LONG)(*Ptr++-'A');
  1191.  
  1192.     return LW;
  1193. }
  1194.  
  1195. BOOL XpkFastModifyFIB( struct FileInfoBlock *FIB ){
  1196.  
  1197.     if( (strncmp( FIB->fib_Comment, XFH_ID, 5 ) != 0) ||
  1198.             (strlen( FIB->fib_Comment ) != 50) ) return FALSE;
  1199.     debug(("XpkFastModifyFIB: header found: %s\n",FIB->fib_Comment));
  1200.  
  1201.     FIB->fib_Comment[0] = '\0';
  1202.     if ( (ATUL( &FIB->fib_Comment[6] ) == FIB->fib_Date.ds_Days) &&
  1203.          (ATUL( &FIB->fib_Comment[15] ) == FIB->fib_Date.ds_Minute) &&
  1204.          (ATUL( &FIB->fib_Comment[24] ) == FIB->fib_Date.ds_Tick) &&
  1205.          (ATUL( &FIB->fib_Comment[33] ) == FIB->fib_Size) ){
  1206.         FIB->fib_Size = ATUL( &FIB->fib_Comment[42] );
  1207.         debug(("XpkFastModifyFIB: header valid, size: %ld\n",FIB->fib_Size));
  1208.             return TRUE;
  1209.     }
  1210.  
  1211.     return FALSE;
  1212. }
  1213.  
  1214. BOOL XpkObjExamine( glb glob, struct XpkLock *lock, struct FileInfoBlock *fib ){
  1215.     BOOL err;
  1216.     struct FileHandle *xfh;
  1217.     
  1218.     debug(("XpkObjExamine(): "));
  1219.     err = xExamine(glob, lock->cfslock.xlock, fib);
  1220.     debug(("%ld,'%s'\n",err,fib->fib_FileName));
  1221.     if( !err ) return err;
  1222.  
  1223.     if( XpkFastModifyFIB( fib ) ) return DOSTRUE;
  1224.  
  1225.     xfh = xOpenFromCopyOfLock( glob, lock->cfslock.xlock );
  1226.     if( !xfh ){
  1227.         debug(("Error: XpkExamine(): Cannot open file from lock %lx.\n",lock));
  1228.         return DOSFALSE;
  1229.     }
  1230.     err = XpkModifyFIB( glob, lock, fib, xfh );
  1231.     if( !err ){
  1232.         LONG saveioerr;
  1233.  
  1234.         saveioerr = glob->ioerr;
  1235.         xClose( glob, xfh );
  1236.         glob->ioerr = saveioerr;
  1237.         return DOSFALSE;
  1238.     }else{
  1239.         xClose( glob, xfh );
  1240.         return DOSTRUE;
  1241.     }
  1242. }
  1243.  
  1244.  
  1245. BOOL XpkObjExamineFH( glb glob, struct XpkFH *fh, struct FileInfoBlock *fib ){
  1246.     BOOL err;
  1247.     
  1248.     debug(("XpkObjExamineFH(): "));
  1249.     err = xExamineFH(glob, fh->cfsfh.xfh, fib);
  1250.     debug(("%ld,'%s'\n",err,fib->fib_FileName));
  1251.     if( !err ) return err;
  1252.  
  1253.     if( (strncmp( fib->fib_Comment, XFH_ID, 5 ) == 0) &&
  1254.             (strlen( fib->fib_Comment ) == 50) ) fib->fib_Comment[0] = '\0';
  1255.         fib->fib_Size = fh->filelen;
  1256.  
  1257.     return DOSTRUE;
  1258. }
  1259.  
  1260.  
  1261. /* XpkModifyFIB() has to fix the length of the file. */
  1262. BOOL XpkModifyFIB( glb glob, struct XpkLock *lock,struct FileInfoBlock *fib, struct FileHandle *xfh ){
  1263.    struct XpkFib xpkfib;
  1264.    
  1265.    if(!XpkExamine_FH(glob, xfh, &xpkfib) )
  1266.    {
  1267.       debug(("Error: IsXpkFile: XpkExamine_FH returned error\n"));
  1268.       return FALSE;
  1269.    }
  1270.    fib->fib_Size = xpkfib.xf_ULen;
  1271.    /* ToDo: Should NOT have fixed block size (look at UFS). */
  1272.    fib->fib_NumBlocks = (fib->fib_Size+BLOCKSIZE-1) / BLOCKSIZE;
  1273.  
  1274.    return DOSTRUE;
  1275. }
  1276.  
  1277.  
  1278. /*------------------------------------------------------------------------*
  1279.  * Initialise and cleanup functions.
  1280.  */
  1281.  
  1282. BOOL InitXpk( glb glob ){
  1283.   
  1284.   if(!(glob->XpkBase = OpenLibrary("xpkmaster.library",0L)))
  1285.       return FALSE;
  1286.    XpkBase = glob->XpkBase;
  1287.    if( ((struct Library *)glob->DOSBase)->lib_Version >= 36){
  1288.       glob->xpkport = NULL;
  1289.    }else{
  1290.       if(!(glob->xpkport=CreatePort("CFS port for KS1.3 Xpk-calls.",0L))){
  1291.          CloseLibrary(glob->XpkBase);
  1292.          debug(("Error creating xpk message port.\n"));
  1293.          return FALSE;
  1294.       }
  1295.    }
  1296.  
  1297.    return TRUE;
  1298. }
  1299.  
  1300.  
  1301. void CleanupXpk( glb glob ){
  1302.    
  1303.    if( glob->xpkport ) DeletePort( glob->xpkport );
  1304.    if( glob->XpkBase ) CloseLibrary( XpkBase );
  1305. }
  1306.  
  1307. /* xScan support */
  1308.  
  1309. static char *ULTA(char *Ptr,ULONG LW)
  1310.  
  1311. {
  1312.  UWORD Index;
  1313.  
  1314.  *Ptr++=' ';
  1315.  for (Index=0; Index<8; Index++, LW>>=4) Ptr[7-Index]='A'+(char)(LW&15);
  1316.  return &Ptr[8];
  1317. }
  1318.  
  1319. void xScan(glb glob,struct FileLock *ParentLock,char *Name)
  1320.  
  1321. {
  1322.  struct FileLock *xScanLock;
  1323.  struct FileHandle *xScanHandle;
  1324.  struct XpkFib XpkFib;
  1325.  
  1326.  if (!glob->xscan) return;
  1327.  
  1328.  debug (("xScan(%lx,%s)\n",ParentLock,Name));
  1329.  
  1330.  if (xScanLock=xLock(glob,ParentLock,Name,ACCESS_READ))
  1331.   {
  1332.    if (xExamine(glob,xScanLock,&glob->fib2))
  1333.     if (xScanHandle=xOpen(glob,ParentLock,Name,MODE_OLDFILE))
  1334.      {
  1335.       if (XpkExamine_FH(glob,xScanHandle,&XpkFib))
  1336.        if ((glob->fib2.fib_Comment[0]=='\0')||
  1337.            (strncmp(glob->fib2.fib_Comment,XFH_ID,strlen(XFH_ID))==0))
  1338.         {
  1339.          char *Ptr;
  1340.  
  1341.          Ptr=strcpy(glob->fib2.fib_Comment,XFH_ID)+strlen(XFH_ID);
  1342.          Ptr=ULTA(Ptr,glob->fib2.fib_Date.ds_Days);
  1343.          Ptr=ULTA(Ptr,glob->fib2.fib_Date.ds_Minute);
  1344.          Ptr=ULTA(Ptr,glob->fib2.fib_Date.ds_Tick);
  1345.          Ptr=ULTA(Ptr,glob->fib2.fib_Size);
  1346.          *ULTA(Ptr,(XpkFib.xf_Type==XPKTYPE_PACKED)?XpkFib.xf_ULen:glob->fib2.fib_Size)='\0';
  1347.  
  1348.          if (!xSetComment(glob,ParentLock,Name,glob->fib2.fib_Comment))
  1349.           debug (("failed to set new comment: %ld\n",glob->ioerr));
  1350.         }
  1351.        else debug (("Comment in use -- nothing done\n"));
  1352.       else debug (("failed to XpkExamine\n"));
  1353.  
  1354.       (void)xClose(glob,xScanHandle);
  1355.      }
  1356.     else debug (("failed to open file\n"));
  1357.    else debug (("failed to examine\n"));
  1358.  
  1359.    (void)xUnLock(glob,xScanLock);
  1360.   }
  1361.  else debug (("failed to open file\n"));
  1362. }
  1363.  
  1364. /* End of xpk.c */
  1365.